﻿namespace NKernel.Core.Impl
{
    using System;
    using System.Collections.Generic;

    using log4net;

    /// <summary>
    /// Class will enforce that each lifecycle method is invoked at most once.
    /// </summary>
    internal class ComponentLifeCycleHandler
    {
        #region Fields

        private readonly ILog logger = LogManager.GetLogger(typeof (ComponentLifeCycleHandler));

        #endregion Fields

        #region Methods

        internal KernelResult Cleanup(IList<IComponentObject> componentObjects)
        {
            foreach (IComponentObject componentObject in componentObjects)
            {
                Cleanup(componentObject);
            }

            return new KernelResult(true);
        }

        internal void Cleanup(IComponentObject componentObject)
        {
            if (componentObject == null || componentObject.State != ComponentStateType.Stopped)
            {
                return;
            }

            if (logger.IsDebugEnabled)
            {
                logger.DebugFormat("Cleaning component {0}", componentObject.ComponentName);
            }
            try
            {
                componentObject.Cleanup();
                componentObject.State = ComponentStateType.Cleaned;
            }
            catch (Exception)
            {
                logger.ErrorFormat("Problem encountered while cleaning up component {0}", componentObject.ComponentName);
            }
        }

        internal KernelResult Init(IList<IComponentObject> componentObjects)
        {
            foreach (IComponentObject componentObject in componentObjects)
            {
                Init(componentObject);
            }

            return new KernelResult(true);
        }

        internal void Init(IComponentObject componentObject)
        {
            if (componentObject == null || componentObject.State != ComponentStateType.Uninitialised)
            {
                return;
            }

            if (logger.IsDebugEnabled)
            {
                logger.DebugFormat("Initialising component {0}", componentObject.ComponentName);
            }
            try
            {
                componentObject.Init();
                componentObject.State = ComponentStateType.Initialised;
            }
            catch (Exception)
            {
               logger.ErrorFormat("Problem encountered while initialising component {0}", componentObject.ComponentName);
            }
        }

        internal KernelResult Start(IList<IComponentObject> componentObjects)
        {
            foreach (IComponentObject componentObject in componentObjects)
            {
                Start(componentObject);
            }

            return new KernelResult(true);
        }

        internal void Start(IComponentObject componentObject)
        {
            if (componentObject == null || componentObject.State != ComponentStateType.Initialised)
            {
                return;
            }

            if (logger.IsDebugEnabled)
            {
                logger.DebugFormat("Starting component {0}", componentObject.ComponentName);
            }

            try
            {
                componentObject.Start();
                componentObject.State = ComponentStateType.Started;
            }
            catch (Exception)
            {
                logger.ErrorFormat("Problem encountered while starting component {0}", componentObject.ComponentName);
            }
        }

        internal KernelResult Stop(IList<IComponentObject> componentObjects)
        {
            foreach (IComponentObject componentObject in componentObjects)
            {
                Stop(componentObject);
            }

            return new KernelResult(true);
        }

        internal void Stop(IComponentObject componentObject)
        {
            if (componentObject == null || componentObject.State != ComponentStateType.Started)
            {
                return;
            }

            if (logger.IsDebugEnabled)
            {
                logger.DebugFormat("Stopping component {0}", componentObject.ComponentName);
            }

            try
            {
                componentObject.Stop();
                componentObject.State = ComponentStateType.Stopped;
            }
            catch (Exception)
            {
                logger.ErrorFormat("Problem encountered while stopping component {0}", componentObject.ComponentName);
            }
        }

        #endregion Methods
    }
}